home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Tool Chest / Dev.CD Feb 97 TC.toast / Sample Code / Files / MoreFiles 1.4.4 / Sources / FSpCompat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-12-17  |  25.6 KB  |  936 lines  |  [TEXT/MPS ]

  1. /*
  2. **    Apple Macintosh Developer Technical Support
  3. **
  4. **    FSSpec compatibility functions.
  5. **
  6. **    by Jim Luther, Apple Developer Technical Support Emeritus
  7. **
  8. **    File:        FSpCompat.c
  9. **
  10. **    Copyright © 1992-1996 Apple Computer, Inc.
  11. **    All rights reserved.
  12. **
  13. **    You may incorporate this sample code into your applications without
  14. **    restriction, though the sample code has been provided "AS IS" and the
  15. **    responsibility for its operation is 100% yours.  However, what you are
  16. **    not permitted to do is to redistribute the source as "DSC Sample Code"
  17. **    after having made changes. If you're going to re-distribute the source,
  18. **    we require that you make it clear in the source that the code was
  19. **    descended from Apple Sample Code, but that you've made changes.
  20. */
  21.  
  22. /*
  23. **    If building application 68K code, set GENERATENODATA to 0 for faster code.
  24. **    If building stand-alone 68K code, set GENERATENODATA to 1 so globals
  25. **        (static variables) are not used.
  26. */
  27. #define    GENERATENODATA 0
  28.  
  29. #include <Types.h>
  30. #include <Errors.h>
  31. #include <LowMem.h>
  32. #include <Gestalt.h>
  33. #include <Resources.h>
  34. #include <Script.h>
  35.  
  36. #define    __COMPILINGMOREFILES
  37.  
  38. #include "MoreFilesExtras.h"
  39. #include "FSpCompat.h"
  40.  
  41. /*****************************************************************************/
  42.  
  43. /* local constants */
  44.  
  45. enum {
  46.     gestaltBugFixAttrsTwo                    = 'bugy',
  47.     gestaltFSpExchangeFilesCompatibilityFix    = 26,
  48.     gestaltBugFixAttrsThree                    = 'bugx',
  49.     gestaltFSpCreateScriptSupportFix        = 1
  50. };
  51.  
  52. /*****************************************************************************/
  53.  
  54. /* static prototypes */
  55.  
  56.  
  57. #if !SystemSevenOrLater
  58. static    Boolean    FSHasFSSpecCalls(void);
  59.  
  60. static    Boolean    QTHasFSSpecCalls(void);
  61. #endif    /* !SystemSevenOrLater */
  62.  
  63. #if !SystemSevenFiveOrLater
  64. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void);
  65. #endif    /* !SystemSevenFiveOrLater */
  66.  
  67. static    Boolean    HasFSpCreateScriptSupportFix(void);
  68.  
  69. #if !SystemSevenFiveOrLater
  70. static    OSErr    GenerateUniqueName(short volume,
  71.                                    long *startSeed,
  72.                                    long dir1,
  73.                                    long dir2,
  74.                                    StringPtr uniqueName);
  75. #endif    /* !SystemSevenFiveOrLater */
  76.  
  77. /*****************************************************************************/
  78.  
  79. /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
  80.  
  81. #if !SystemSevenOrLater
  82. static    Boolean    FSHasFSSpecCalls(void)
  83. {
  84.     long            response;
  85. #if !GENERATENODATA
  86.     static Boolean    tested = false;
  87.     static Boolean    result = false;
  88. #else
  89.     Boolean    result = false;
  90. #endif
  91.     
  92. #if !GENERATENODATA
  93.     if ( !tested )
  94.     {
  95.         tested = true;
  96. #endif
  97.         if ( Gestalt(gestaltFSAttr, &response) == noErr )
  98.         {
  99.             result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
  100.         }
  101. #if !GENERATENODATA
  102.     }
  103. #endif
  104.     return ( result );
  105. }
  106. #endif    /* !SystemSevenOrLater */
  107.  
  108. /*****************************************************************************/
  109.  
  110. /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
  111. /* except for FSpExchangeFiles. */
  112.  
  113. #if !SystemSevenOrLater
  114. static    Boolean    QTHasFSSpecCalls(void)
  115. {
  116.     long            response;
  117. #if !GENERATENODATA
  118.     static Boolean    tested = false;
  119.     static Boolean    result = false;
  120. #else
  121.     Boolean    result = false;
  122. #endif
  123.     
  124. #if !GENERATENODATA
  125.     if ( !tested )
  126.     {
  127.         tested = true;
  128. #endif
  129.         result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
  130. #if !GENERATENODATA
  131.     }
  132. #endif
  133.     return ( result );
  134. }
  135. #endif    /* !SystemSevenOrLater */
  136.  
  137. /*****************************************************************************/
  138.  
  139. /* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
  140. /* compatibility code has been fixed in system software. */
  141. /* This was fixed by System Update 3.0, so if SystemSevenFiveOrLater */
  142. /* is true, then we know the fix is in. */
  143.  
  144. #if !SystemSevenFiveOrLater
  145. static    Boolean    HasFSpExchangeFilesCompatibilityFix(void)
  146. {
  147.     long            response;
  148. #if !GENERATENODATA
  149.     static Boolean    tested = false;
  150.     static Boolean    result = false;
  151. #else    /* !GENERATENODATA */
  152.     Boolean    result = false;
  153. #endif    /* !GENERATENODATA */
  154.     
  155. #if !GENERATENODATA
  156.     if ( !tested )
  157.     {
  158.         tested = true;
  159. #endif    /* !GENERATENODATA */
  160.         if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
  161.         {
  162.             result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
  163.         }
  164. #if !GENERATENODATA
  165.     }
  166. #endif    /* !GENERATENODATA */
  167.     return ( result );
  168. }
  169. #endif    /* !SystemSevenFiveOrLater */
  170.  
  171. /*****************************************************************************/
  172.  
  173. /* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
  174. /* FSpCreateResFile have been fixed in system software to correctly set */
  175. /* the scriptCode in the volume's catalog. */
  176. /* This was fixed by System 7.5 Update 1.0 */
  177.  
  178. static    Boolean    HasFSpCreateScriptSupportFix(void)
  179. {
  180.     long            response;
  181. #if !GENERATENODATA
  182.     static Boolean    tested = false;
  183.     static Boolean    result = false;
  184. #else
  185.     Boolean    result = false;
  186. #endif    /* !GENERATENODATA */
  187.     
  188. #if !GENERATENODATA
  189.     if ( !tested )
  190.     {
  191.         tested = true;
  192. #endif    /* !GENERATENODATA */
  193.         if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
  194.         {
  195.             result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
  196.         }
  197. #if !GENERATENODATA
  198.     }
  199. #endif    /* !GENERATENODATA */
  200.     return ( result );
  201. }
  202.  
  203. /*****************************************************************************/
  204.  
  205. /*
  206. **    File Manager FSp calls
  207. */
  208.  
  209. /*****************************************************************************/
  210.  
  211. pascal    OSErr    FSMakeFSSpecCompat(short vRefNum,
  212.                                    long dirID,
  213.                                    ConstStr255Param fileName,
  214.                                    FSSpec *spec)
  215. {
  216.     OSErr    result;
  217.     
  218. #if !SystemSevenOrLater
  219.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  220. #endif    /* !SystemSevenOrLater */
  221.     {
  222.         /* Let the file system create the FSSpec if it can since it does the job */
  223.         /* much more efficiently than I can. */
  224.         result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
  225.         /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
  226.         /* returned in the parID field when making an FSSpec to the volume's */
  227.         /* root directory by passing a full pathname in MakeFSSpec's */
  228.         /* fileName parameter. */
  229.         if ( (result == noErr) && (spec->parID == 0) )
  230.             spec->parID = fsRtParID;
  231.     }
  232. #if !SystemSevenOrLater
  233.     else
  234.     {
  235.         Boolean    isDirectory;
  236.         
  237.         result = GetObjectLocation(vRefNum, dirID, fileName,
  238.                                     &(spec->vRefNum), &(spec->parID), spec->name,
  239.                                     &isDirectory);
  240.     }
  241. #endif    /* !SystemSevenOrLater */
  242.     return ( result );
  243. }
  244.  
  245. /*****************************************************************************/
  246.  
  247. pascal    OSErr    FSpOpenDFCompat(const FSSpec *spec,
  248.                                 char permission,
  249.                                 short *refNum)
  250. {
  251. #if !SystemSevenOrLater
  252.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  253. #endif    /* !SystemSevenOrLater */
  254.     {
  255.         return ( FSpOpenDF(spec, permission, refNum) );
  256.     }
  257. #if !SystemSevenOrLater
  258.     else
  259.     {
  260.         OSErr            result;
  261.         HParamBlockRec    pb;
  262.         
  263.         pb.ioParam.ioVRefNum = spec->vRefNum;
  264.         pb.fileParam.ioDirID = spec->parID;
  265.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  266.         pb.ioParam.ioVersNum = 0;
  267.         pb.ioParam.ioPermssn = permission;
  268.         pb.ioParam.ioMisc = NULL;
  269.         result = PBHOpenSync(&pb);    /* OpenDF not supported by System 6, so use Open */
  270.         *refNum = pb.ioParam.ioRefNum;
  271.         return ( result );
  272.     }
  273. #endif    /* !SystemSevenOrLater */
  274. }
  275.  
  276. /*****************************************************************************/
  277.  
  278. pascal    OSErr    FSpOpenRFCompat(const FSSpec *spec,
  279.                                 char permission,
  280.                                 short *refNum)
  281. {
  282. #if !SystemSevenOrLater
  283.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  284. #endif    /* !SystemSevenOrLater */
  285.     {
  286.         return ( FSpOpenRF(spec, permission, refNum) );
  287.     }
  288. #if !SystemSevenOrLater
  289.     else
  290.     {
  291.         OSErr            result;
  292.         HParamBlockRec    pb;
  293.         
  294.         pb.ioParam.ioVRefNum = spec->vRefNum;
  295.         pb.fileParam.ioDirID = spec->parID;
  296.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  297.         pb.ioParam.ioVersNum = 0;
  298.         pb.ioParam.ioPermssn = permission;
  299.         pb.ioParam.ioMisc = NULL;
  300.         result = PBHOpenRFSync(&pb);
  301.         *refNum = pb.ioParam.ioRefNum;
  302.         return ( result );
  303.     }
  304. #endif    /* !SystemSevenOrLater */
  305. }
  306.  
  307. /*****************************************************************************/
  308.  
  309. pascal    OSErr    FSpCreateCompat(const FSSpec *spec,
  310.                                 OSType creator,
  311.                                 OSType fileType,
  312.                                 ScriptCode scriptTag)
  313. {
  314.     OSErr            result;
  315.     UniversalFMPB    pb;
  316.     
  317.     /* There's no conditional to test for, so this test must be made */
  318.     if ( HasFSpCreateScriptSupportFix() )
  319.     {
  320.         return ( FSpCreate(spec, creator, fileType, scriptTag) );
  321.     }
  322.     /*    If FSpCreate isn't called, this code will be executed */
  323.     pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  324.     pb.hPB.fileParam.ioDirID = spec->parID;
  325.     pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  326.     pb.hPB.fileParam.ioFVersNum = 0;
  327.     result = PBHCreateSync(&(pb.hPB));
  328.     if ( result == noErr )
  329.     {
  330.         /* get info on created item */
  331.         pb.ciPB.hFileInfo.ioFDirIndex = 0;
  332.         result = PBGetCatInfoSync(&(pb.ciPB));
  333.         if ( result == noErr )
  334.         {
  335.             /* Set fdScript in FXInfo */
  336.             /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  337.             /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  338.             /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  339.             pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  340.                                                         ((char)scriptTag | (char)0x80) :
  341.                                                         (smRoman);
  342.             /* Set creator/fileType */
  343.             pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  344.             pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
  345.             /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  346.             pb.ciPB.hFileInfo.ioDirID = spec->parID;
  347.             result = PBSetCatInfoSync(&(pb.ciPB));
  348.         }
  349.     }
  350.     return ( result );
  351. }
  352.  
  353. /*****************************************************************************/
  354.  
  355. pascal    OSErr    FSpDirCreateCompat(const FSSpec *spec,
  356.                                    ScriptCode scriptTag,
  357.                                    long *createdDirID)
  358. {
  359. #if !SystemSevenOrLater
  360.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  361. #endif    /* !SystemSevenOrLater */
  362.     {
  363.         return ( FSpDirCreate(spec, scriptTag, createdDirID) );
  364.     }
  365. #if !SystemSevenOrLater
  366.     else
  367.     {
  368.         OSErr            result;
  369.         UniversalFMPB    pb;
  370.         
  371.         pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
  372.         pb.hPB.fileParam.ioDirID = spec->parID;
  373.         pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  374.         result = PBDirCreateSync(&(pb.hPB));
  375.         *createdDirID = pb.hPB.fileParam.ioDirID;
  376.         if ( result == noErr )
  377.         {
  378.             /* get info on created item */
  379.             pb.ciPB.dirInfo.ioFDirIndex = 0;
  380.             pb.ciPB.dirInfo.ioDrDirID = spec->parID;
  381.             result = PBGetCatInfoSync(&(pb.ciPB));
  382.             if ( result == noErr )
  383.             {
  384.                 /* Set frScript in DXInfo */
  385.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  386.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  387.                 /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
  388.                 pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
  389.                                                             ((char)scriptTag | (char)0x80) :
  390.                                                             (smRoman);
  391.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  392.                 pb.ciPB.dirInfo.ioDrDirID = spec->parID;            
  393.                 result = PBSetCatInfoSync(&(pb.ciPB));
  394.             }
  395.         }
  396.         return ( result );
  397.     }
  398. #endif    /* !SystemSevenOrLater */
  399. }
  400.  
  401. /*****************************************************************************/
  402.  
  403. pascal    OSErr    FSpDeleteCompat(const FSSpec *spec)
  404. {
  405. #if !SystemSevenOrLater
  406.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  407. #endif    /* !SystemSevenOrLater */
  408.     {
  409.         return ( FSpDelete(spec) );
  410.     }
  411. #if !SystemSevenOrLater
  412.     else
  413.     {
  414.         HParamBlockRec    pb;
  415.         
  416.         pb.ioParam.ioVRefNum = spec->vRefNum;
  417.         pb.fileParam.ioDirID = spec->parID;
  418.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  419.         pb.ioParam.ioVersNum = 0;
  420.         return ( PBHDeleteSync(&pb) );
  421.     }
  422. #endif    /* !SystemSevenOrLater */
  423. }
  424.  
  425. /*****************************************************************************/
  426.  
  427. pascal    OSErr    FSpGetFInfoCompat(const FSSpec *spec,
  428.                                   FInfo *fndrInfo)
  429. {
  430. #if !SystemSevenOrLater
  431.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  432. #endif    /* !SystemSevenOrLater */
  433.     {
  434.         return ( FSpGetFInfo(spec, fndrInfo) );
  435.     }
  436. #if !SystemSevenOrLater
  437.     else
  438.     {
  439.         OSErr            result;
  440.         HParamBlockRec    pb;
  441.         
  442.         pb.fileParam.ioVRefNum = spec->vRefNum;
  443.         pb.fileParam.ioDirID = spec->parID;
  444.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  445.         pb.fileParam.ioFVersNum = 0;
  446.         pb.fileParam.ioFDirIndex = 0;
  447.         result = PBHGetFInfoSync(&pb);
  448.         *fndrInfo = pb.fileParam.ioFlFndrInfo;
  449.         return ( result );
  450.     }
  451. #endif    /* !SystemSevenOrLater */
  452. }
  453.  
  454. /*****************************************************************************/
  455.  
  456. pascal    OSErr    FSpSetFInfoCompat(const FSSpec *spec,
  457.                                   const FInfo *fndrInfo)
  458. {
  459. #if !SystemSevenOrLater
  460.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  461. #endif    /* !SystemSevenOrLater */
  462.     {
  463.         return ( FSpSetFInfo(spec, fndrInfo) );
  464.     }
  465. #if !SystemSevenOrLater
  466.     else
  467.     {
  468.         OSErr            result;
  469.         HParamBlockRec    pb;
  470.         
  471.         pb.fileParam.ioVRefNum = spec->vRefNum;
  472.         pb.fileParam.ioDirID = spec->parID;
  473.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  474.         pb.fileParam.ioFVersNum = 0;
  475.         pb.fileParam.ioFDirIndex = 0;
  476.         result = PBHGetFInfoSync(&pb);
  477.         if ( result == noErr )
  478.         {
  479.             pb.fileParam.ioFlFndrInfo = *fndrInfo;
  480.             pb.fileParam.ioDirID = spec->parID;
  481.             result = PBHSetFInfoSync(&pb);
  482.         }
  483.         return ( result );
  484.     }
  485. #endif    /* !SystemSevenOrLater */
  486. }
  487.  
  488. /*****************************************************************************/
  489.  
  490. pascal    OSErr    FSpSetFLockCompat(const FSSpec *spec)
  491. {
  492. #if !SystemSevenOrLater
  493.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  494. #endif    /* !SystemSevenOrLater */
  495.     {
  496.         return ( FSpSetFLock(spec) );
  497.     }
  498. #if !SystemSevenOrLater
  499.     else
  500.     {
  501.         HParamBlockRec    pb;
  502.         
  503.         pb.fileParam.ioVRefNum = spec->vRefNum;
  504.         pb.fileParam.ioDirID = spec->parID;
  505.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  506.         pb.fileParam.ioFVersNum = 0;
  507.         return ( PBHSetFLockSync(&pb) );
  508.     }
  509. #endif    /* !SystemSevenOrLater */
  510. }
  511.  
  512. /*****************************************************************************/
  513.  
  514. pascal    OSErr    FSpRstFLockCompat(const FSSpec *spec)
  515. {
  516. #if !SystemSevenOrLater
  517.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  518. #endif    /* !SystemSevenOrLater */
  519.     {
  520.         return ( FSpRstFLock(spec) );
  521.     }
  522. #if !SystemSevenOrLater
  523.     else
  524.     {
  525.         HParamBlockRec    pb;
  526.         
  527.         pb.fileParam.ioVRefNum = spec->vRefNum;
  528.         pb.fileParam.ioDirID = spec->parID;
  529.         pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
  530.         pb.fileParam.ioFVersNum = 0;
  531.         return ( PBHRstFLockSync(&pb) );
  532.     }
  533. #endif    /* !SystemSevenOrLater */
  534. }
  535.  
  536. /*****************************************************************************/
  537.  
  538. pascal    OSErr    FSpRenameCompat(const FSSpec *spec,
  539.                                 ConstStr255Param newName)
  540. {
  541. #if !SystemSevenOrLater
  542.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  543. #endif    /* !SystemSevenOrLater */
  544.     {
  545.         return ( FSpRename(spec, newName) );
  546.     }
  547. #if !SystemSevenOrLater
  548.     else
  549.     {
  550.         HParamBlockRec    pb;
  551.         
  552.         pb.ioParam.ioVRefNum = spec->vRefNum;
  553.         pb.fileParam.ioDirID = spec->parID;
  554.         pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
  555.         pb.ioParam.ioVersNum = 0;
  556.         pb.ioParam.ioMisc = (Ptr) newName;
  557.         return ( PBHRenameSync(&pb) );
  558.     }
  559. #endif    /* !SystemSevenOrLater */
  560. }
  561.  
  562. /*****************************************************************************/
  563.  
  564. pascal    OSErr    FSpCatMoveCompat(const FSSpec *source,
  565.                                  const FSSpec *dest)
  566. {
  567. #if !SystemSevenOrLater
  568.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  569. #endif    /* !SystemSevenOrLater */
  570.     {
  571.         return ( FSpCatMove(source, dest) );
  572.     }
  573. #if !SystemSevenOrLater
  574.     else
  575.     {
  576.         CMovePBRec    pb;
  577.         
  578.         /* source and destination volume must be the same */
  579.         if ( source->vRefNum != dest->vRefNum )
  580.             return ( paramErr );
  581.         
  582.         pb.ioNamePtr = (StringPtr) &(source->name);
  583.         pb.ioVRefNum = source->vRefNum;
  584.         pb.ioDirID = source->parID;
  585.         pb.ioNewDirID = dest->parID;
  586.         pb.ioNewName = (StringPtr) &(dest->name);
  587.         return ( PBCatMoveSync(&pb) );
  588.     }
  589. #endif    /* !SystemSevenOrLater */
  590. }
  591.  
  592. /*****************************************************************************/
  593.  
  594. /* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
  595. /* on the specified volume. Ripped off from Feldman's code. */
  596.  
  597. #if !SystemSevenFiveOrLater
  598. static    OSErr    GenerateUniqueName(short volume,
  599.                                    long *startSeed,
  600.                                    long dir1,
  601.                                    long dir2,
  602.                                    StringPtr uniqueName)
  603. {
  604.     OSErr            error = noErr;
  605.     long            i;
  606.     CInfoPBRec        cinfo;
  607.     unsigned char    hexStr[16];
  608.     
  609.     for ( i = 0; i < 16; ++i )
  610.     {
  611.         if ( i < 10 )
  612.         {
  613.             hexStr[i] = 0x30 + i;
  614.         }
  615.         else
  616.         {
  617.             hexStr[i] = 0x37 + i;
  618.         }
  619.     }
  620.     
  621.     cinfo.hFileInfo.ioVRefNum = volume;
  622.     cinfo.hFileInfo.ioFDirIndex = 0;
  623.     cinfo.hFileInfo.ioNamePtr = uniqueName;
  624.  
  625.     while ( error != fnfErr )
  626.     {
  627.         (*startSeed)++;        
  628.         cinfo.hFileInfo.ioNamePtr[0] = 8;
  629.         for ( i = 1; i <= 8; i++ )
  630.         {
  631.             cinfo.hFileInfo.ioNamePtr[i] = hexStr[((*startSeed >> ((8-i)*4)) & 0xf)];
  632.         }
  633.         cinfo.hFileInfo.ioDirID = dir1;
  634.         error = fnfErr;
  635.         for ( i = 1; i <= 2; i++ )
  636.         {
  637.             error = error & PBGetCatInfoSync(&cinfo);
  638.             cinfo.hFileInfo.ioDirID = dir2;
  639.             if ( (error != fnfErr) && (error != noErr) )
  640.             {
  641.                 return ( error );
  642.             }
  643.         }
  644.     }
  645.     return ( noErr );
  646. }
  647. #endif    /* !SystemSevenFiveOrLater */
  648.  
  649. /*****************************************************************************/
  650.  
  651. pascal    OSErr    FSpExchangeFilesCompat(const FSSpec *source,
  652.                                        const FSSpec *dest)
  653. {
  654. #if !SystemSevenOrLater
  655.     if ( FSHasFSSpecCalls() )
  656. #endif    /* !SystemSevenOrLater */
  657.     {
  658. #if !SystemSevenFiveOrLater
  659.         if ( HasFSpExchangeFilesCompatibilityFix() )
  660. #endif    /* !SystemSevenFiveOrLater */
  661.         {
  662.             return ( FSpExchangeFiles(source, dest) );
  663.         }
  664.     }
  665. #if !SystemSevenFiveOrLater
  666.     /*    If FSpExchangeFiles isn't called, this code will be executed */
  667.     {
  668.         HParamBlockRec            pb;
  669.         CInfoPBRec                catInfoSource, catInfoDest;
  670.         OSErr                    result, result2;
  671.         Str31                    unique1, unique2;
  672.         StringPtr                unique1Ptr, unique2Ptr, swapola;
  673.         GetVolParmsInfoBuffer    volInfo;
  674.         long                    theSeed, temp;
  675.         
  676.         /* Make sure the source and destination are on the same volume */
  677.         if ( source->vRefNum != dest->vRefNum )
  678.         {
  679.             result = diffVolErr;
  680.             goto errorExit3;
  681.         }
  682.         
  683.         /* Try PBExchangeFiles first since it preserves the file ID reference */
  684.         pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
  685.         pb.fidParam.ioVRefNum = source->vRefNum;
  686.         pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
  687.         pb.fidParam.ioDestDirID = dest->parID;
  688.         pb.fidParam.ioSrcDirID = source->parID;
  689.     
  690.         result = PBExchangeFilesSync(&pb);
  691.     
  692.         /* Note: The compatibility case won't work for files with *Btree control blocks. */
  693.         /* Right now the only *Btree files are created by the system. */
  694.         if ( result != noErr )
  695.         {
  696.             pb.ioParam.ioNamePtr = NULL;
  697.             pb.ioParam.ioBuffer = (Ptr) &volInfo;
  698.             pb.ioParam.ioReqCount = sizeof(volInfo);
  699.             result2 = PBHGetVolParmsSync(&pb);
  700.             
  701.             /* continue if volume has no fileID support (or no GetVolParms support) */
  702.             if ( (result2 == noErr) && hasFileIDs(volInfo) )
  703.             {
  704.                 goto errorExit3;
  705.             }
  706.     
  707.             /* Get the catalog information for each file */
  708.             /* and make sure both files are *really* files */
  709.             catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
  710.             catInfoSource.hFileInfo.ioFDirIndex = 0;
  711.             catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
  712.             catInfoSource.hFileInfo.ioDirID = source->parID;
  713.             catInfoSource.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
  714.             result = PBGetCatInfoSync(&catInfoSource);
  715.             if ( result != noErr )
  716.             {
  717.                 goto errorExit3;
  718.             }
  719.             if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  720.             {
  721.                 result = notAFileErr;
  722.                 goto errorExit3;
  723.             }
  724.             
  725.             catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
  726.             catInfoDest.hFileInfo.ioFDirIndex = 0;
  727.             catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
  728.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  729.             catInfoDest.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
  730.             result = PBGetCatInfoSync(&catInfoDest);
  731.             if ( result != noErr )
  732.             {
  733.                 goto errorExit3;
  734.             }
  735.             if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  736.             {
  737.                 result = notAFileErr;
  738.                 goto errorExit3;
  739.             }
  740.             
  741.             /* generate 2 filenames that are unique in both directories */
  742.             theSeed = 0x64666A6C;    /* a fine unlikely filename */
  743.             unique1Ptr = (StringPtr)&unique1;
  744.             unique2Ptr = (StringPtr)&unique2;
  745.             
  746.             result = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
  747.             if ( result != noErr )
  748.             {
  749.                 goto errorExit3;
  750.             }
  751.     
  752.             GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
  753.             if ( result != noErr )
  754.             {
  755.                 goto errorExit3;
  756.             }
  757.     
  758.             /* rename source to unique1 */
  759.             pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
  760.             pb.ioParam.ioMisc = (Ptr) unique1Ptr;
  761.             pb.ioParam.ioVersNum = 0;
  762.             result = PBHRenameSync(&pb);
  763.             if ( result != noErr )
  764.             {
  765.                 goto errorExit3;
  766.             }
  767.             
  768.             /* rename dest to unique2 */
  769.             pb.ioParam.ioMisc = (Ptr) unique2Ptr;
  770.             pb.ioParam.ioVersNum = 0;
  771.             pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
  772.             pb.fileParam.ioDirID = dest->parID;
  773.             result = PBHRenameSync(&pb);
  774.             if ( result != noErr )
  775.             {
  776.                 goto errorExit2;    /* back out gracefully by renaming unique1 back to source */
  777.             }
  778.                 
  779.             /* If files are not in same directory, swap their locations */
  780.             if ( source->parID != dest->parID )
  781.             {
  782.                 /* move source file to dest directory */
  783.                 pb.copyParam.ioNamePtr = unique1Ptr;
  784.                 pb.copyParam.ioNewName = NULL;
  785.                 pb.copyParam.ioNewDirID = dest->parID;
  786.                 pb.copyParam.ioDirID = source->parID;
  787.                 result = PBCatMoveSync((CMovePBPtr) &pb);
  788.                 if ( result != noErr )
  789.                 {
  790.                     goto errorExit1;    /* back out gracefully by renaming both files to original names */
  791.                 }
  792.                 
  793.                 /* move dest file to source directory */
  794.                 pb.copyParam.ioNamePtr = unique2Ptr;
  795.                 pb.copyParam.ioNewDirID = source->parID;
  796.                 pb.copyParam.ioDirID = dest->parID;
  797.                 result = PBCatMoveSync((CMovePBPtr) &pb);
  798.                 if ( result != noErr)
  799.                 {
  800.                     /* life is very bad.  We'll at least try to move source back */
  801.                     pb.copyParam.ioNamePtr = unique1Ptr;
  802.                     pb.copyParam.ioNewName = NULL;
  803.                     pb.copyParam.ioNewDirID = source->parID;
  804.                     pb.copyParam.ioDirID = dest->parID;
  805.                     (void) PBCatMoveSync((CMovePBPtr) &pb);    /* ignore errors */
  806.                     goto errorExit1;    /* back out gracefully by renaming both files to original names */
  807.                 }
  808.             }
  809.             
  810.             /* Make unique1Ptr point to file in source->parID */
  811.             /* and unique2Ptr point to file in dest->parID */
  812.             /* This lets us fall through to the rename code below */
  813.             swapola = unique1Ptr;
  814.             unique1Ptr = unique2Ptr;
  815.             unique2Ptr = swapola;
  816.     
  817.             /* At this point, the files are in their new locations (if they were moved) */
  818.             /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
  819.             /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
  820.             /* Need to swap attributes except mod date and swap names */
  821.     
  822.             /* swap the catalog info by re-aiming the CInfoPB's */
  823.             catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
  824.             catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
  825.             
  826.             catInfoSource.hFileInfo.ioDirID = source->parID;
  827.             catInfoDest.hFileInfo.ioDirID = dest->parID;
  828.             
  829.             /* Swap the original mod dates with each file */
  830.             temp = catInfoSource.hFileInfo.ioFlMdDat;
  831.             catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
  832.             catInfoDest.hFileInfo.ioFlMdDat = temp;
  833.             
  834.             /* Here's the swap (ignore errors) */
  835.             (void) PBSetCatInfoSync(&catInfoSource); 
  836.             (void) PBSetCatInfoSync(&catInfoDest);
  837.             
  838.             /* rename unique2 back to dest */
  839. errorExit1:
  840.             pb.ioParam.ioMisc = (Ptr) &(dest->name);
  841.             pb.ioParam.ioVersNum = 0;
  842.             pb.fileParam.ioNamePtr = unique2Ptr;
  843.             pb.fileParam.ioDirID = dest->parID;
  844.             (void) PBHRenameSync(&pb);    /* ignore errors */
  845.     
  846.             /* rename unique1 back to source */
  847. errorExit2:
  848.             pb.ioParam.ioMisc = (Ptr) &(source->name);
  849.             pb.ioParam.ioVersNum = 0;
  850.             pb.fileParam.ioNamePtr = unique1Ptr;
  851.             pb.fileParam.ioDirID = source->parID;
  852.             (void) PBHRenameSync(&pb); /* ignore errors */
  853.         }
  854. errorExit3: { /* null statement */ }
  855.         return ( result );
  856.     }
  857. #endif    /* !SystemSevenFiveOrLater */
  858. }
  859.  
  860. /*****************************************************************************/
  861.  
  862. /* 
  863. **    Resource Manager FSp calls
  864. */
  865.  
  866. /*****************************************************************************/
  867.  
  868. pascal    short    FSpOpenResFileCompat(const FSSpec *spec,
  869.                                      SignedByte permission)
  870. {
  871. #if !SystemSevenOrLater
  872.     if ( FSHasFSSpecCalls() || QTHasFSSpecCalls() )
  873. #endif    /* !SystemSevenOrLater */
  874.     {
  875.         return ( FSpOpenResFile(spec, permission) );
  876.     }
  877. #if !SystemSevenOrLater
  878.     else
  879.     {
  880.         return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
  881.     }
  882. #endif    /* !SystemSevenOrLater */
  883. }
  884.  
  885. /*****************************************************************************/
  886.  
  887. pascal    void    FSpCreateResFileCompat(const FSSpec *spec,
  888.                                        OSType creator,
  889.                                        OSType fileType,
  890.                                        ScriptCode scriptTag)
  891. {    
  892.     if ( HasFSpCreateScriptSupportFix() )
  893.     {
  894.         FSpCreateResFile(spec, creator, fileType, scriptTag);
  895.         return;
  896.     }
  897.     /*    If FSpCreateResFile isn't called, this code will be executed */
  898.     {
  899.         OSErr            result;
  900.         CInfoPBRec        pb;
  901.         
  902.         HCreateResFile(spec->vRefNum, spec->parID, spec->name);
  903.         if ( ResError() == noErr )
  904.         {
  905.             /* get info on created item */
  906.             pb.hFileInfo.ioVRefNum = spec->vRefNum;
  907.             pb.hFileInfo.ioDirID = spec->parID;
  908.             pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
  909.             pb.hFileInfo.ioFDirIndex = 0;
  910.             result = PBGetCatInfoSync(&pb);
  911.             if ( result == noErr )
  912.             {
  913.                 /* Set fdScript in FXInfo */
  914.                 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
  915.                 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
  916.                 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
  917.                 pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
  918.                                                         ((char)scriptTag | (char)0x80) :
  919.                                                         (smRoman);
  920.                 /* Set creator/fileType */
  921.                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  922.                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
  923.                 
  924.                 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
  925.                 pb.hFileInfo.ioDirID = spec->parID;
  926.                 result = PBSetCatInfoSync(&pb);
  927.             }
  928.             /* Set ResErr low memory global to result */
  929.             LMSetResErr(result);
  930.         }
  931.         return;
  932.     }
  933. }
  934.  
  935. /*****************************************************************************/
  936.